package com.flyqiu.form.api.store;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flyqiu.common.mybaits.plus.FlyQiuQueryWrapper;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import com.flyqiu.form.api.FlyQiuFormContext;
import com.flyqiu.form.api.event.FlyQiuTableDataEventManage;
import com.flyqiu.form.api.event.FlyQiuTableEventManage;
import com.flyqiu.form.api.invoke.FlyQiuFormDataDeleteInvoke;
import com.flyqiu.form.api.rule.FlyQiuDataRuleManage;
import com.flyqiu.form.api.service.FlyQiuTableConfigService;
import com.flyqiu.form.api.tools.FlyQiuAvueColTools;
import com.flyqiu.form.api.tools.FlyQiuTableOptionTools;
import com.flyqiu.form.common.FlyQiuFormDataDelMode;
import com.flyqiu.form.common.enums.FlyQiuFormDataAction;
import com.flyqiu.form.common.exceptions.FlyQiuFormException;
import com.flyqiu.form.model.FlyQiuColumnInfo;
import com.flyqiu.form.model.FlyQiuTableConfigModel;
import com.flyqiu.form.model.SqlColumnModel;
import com.flyqiu.form.model.entity.FlyQiuTableConfig;
import com.flyqiu.form.model.enums.FlyQiuFormDeploymentStatus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.sql.SQLSyntaxErrorException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 基础表单存储服务抽象类。
 */
@Slf4j
public abstract class FlyQiuBaseFormStorageService implements FlyQiuFormStoreService {

    protected final FlyQiuAvueDynamicService flyQiuAvueDynamicService;
    private final FlyQiuTableConfigService flyQiuTableConfigService;
    private final FlyQiuTableEventManage formEventManage;
    private final FlyQiuTableDataEventManage formDataEventManage;
    private final FlyQiuDataRuleManage flyQiuDataRuleManage;

    /**
     * 构造函数，初始化依赖服务。
     *
     * @param formContext 表单上下文
     */
    public FlyQiuBaseFormStorageService(FlyQiuFormContext formContext) {
        formEventManage = formContext.getFormEventManage();
        formDataEventManage = formContext.getFormDataEventManage();
        flyQiuAvueDynamicService = formContext.getAvueDynamicService();
        flyQiuDataRuleManage = formContext.getFlyQiuDataRuleManage();
        this.flyQiuTableConfigService = formContext.getTableConfigService();
    }

    /**
     * 更新表单配置中的列信息。
     *
     * @param startFormColumns 初始列信息
     * @param tableOption      表单配置
     */
    private static void updateTableOption(List<SqlColumnModel> startFormColumns, JSONObject tableOption) {
        JSONArray columns = FlyQiuTableOptionTools.getColumns(tableOption, true);
        Map<String, SqlColumnModel> sqlColMap = startFormColumns.stream()
                .collect(Collectors.toMap(SqlColumnModel::getProp, e -> e));
        String prop;
        for (int i = 0; i < columns.size(); i++) {
            JSONObject col = columns.getJSONObject(i);
            prop = col.getString("prop");
            if (StringUtils.isBlank(prop)) {
                continue;
            }
            SqlColumnModel columnModel = sqlColMap.get(prop);
            if (columnModel == null) continue;
            col.put("id", columnModel.getId());
            col.put("sqlDataType", columnModel.getSqlDataType());
            if (columnModel.getSqlDataLength() != null && columnModel.getSqlDataLength() > 0) {
                col.put("sqlDataLength", columnModel.getSqlDataLength());
            }
            if (columnModel.getPrecision() != null && columnModel.getPrecision() > 0) {
                col.put("precision", columnModel.getPrecision());
            }
        }
    }

    /**
     * 获取表单的列配置信息。
     *
     * @param tableId 表单 ID
     * @return 列配置信息列表
     */
    @Override
    public List<SqlColumnModel> getStorageColumnConfig(String tableId) {
        FlyQiuTableConfigModel table = getTableConfigModel(tableId);
        return getStorageColumnConfig(table);
    }

    /**
     * 获取表配置模型。
     *
     * @param tableId       表 ID
     * @param loadSqlColumn 是否加载列信息
     * @return 表配置模型
     */
    @Override
    public FlyQiuTableConfigModel getTableConfigModel(String tableId, boolean loadSqlColumn) {
        FlyQiuTableConfig config = flyQiuTableConfigService.getById(tableId);
        if (config == null) return null;
        return getTableConfigModel(config, loadSqlColumn);
    }

    /**
     * 获取表配置模型。
     *
     * @param config        表配置
     * @param loadSqlColumn 是否加载列信息
     * @return 表配置模型
     */
    @Override
    public final FlyQiuTableConfigModel getTableConfigModel(FlyQiuTableConfig config, boolean loadSqlColumn) {
        FlyQiuTableConfigModel model;
        if (!(config instanceof FlyQiuTableConfigModel)) {
            model = JSONObject.from(config).toJavaObject(FlyQiuTableConfigModel.class);
        } else {
            model = (FlyQiuTableConfigModel) config;
        }
        if (!loadSqlColumn) return model;
        if (model.getSqlColumns() != null && !model.getSqlColumns().isEmpty()) return model;
        List<SqlColumnModel> column = this.getStorageColumnConfig(model);
        model.setSqlColumns(column);
        return model;
    }

    /**
     * 创建表。
     *
     * @param config 表配置
     */
    @Override
    public void createTable(FlyQiuTableConfig config) {
        formEventManage.beforeCreateTable(config);
        if (StringUtils.isAllBlank(config.getFormCode())) {
            config.setFormCode(config.getTableName());
        }
        flyQiuTableConfigService.save(config);
        formEventManage.afterCreateTable(config);
    }

    /**
     * 更新表。
     *
     * @param config 表配置
     */
    @Override
    public void updateTable(FlyQiuTableConfig config) {
        List<SqlColumnModel> tableColumnsOld = this.getStorageColumnConfig(config);
        JSONObject formOption = config.getFormOption();
        if (formOption == null || formOption.isEmpty()) {
            throw new FlyQiuFormException("未找到有效的表单配置");
        }
        formEventManage.beforeUpdateTable(config, tableColumnsOld);
        Integer deploymentStatus = config.getDeploymentStatus();
        if (hasSynchronizationTable(config)) {
            deploymentStatus = 0;
        }
        config.setDeploymentStatus(deploymentStatus);
        flyQiuTableConfigService.updateById(config);
        formEventManage.afterUpdateTable(config);
    }

    /**
     * 检查是否需要同步表单。
     *
     * @param config 表配置
     * @return 是否需要同步
     */
    private boolean hasSynchronizationTable(FlyQiuTableConfig config) {
        if (FlyQiuCollectionTools.isEmpty(config.getFormOption())) {
            throw new FlyQiuFormException("未找到有效的表单配置: " + config.getFormCode());
        }
        JSONArray columns = FlyQiuTableOptionTools.getColumns(config.getFormOption(), true);
        List<JSONObject> avueDynamics = FlyQiuAvueColTools.getTableAvueDynamics(columns);
        for (JSONObject dynamic : avueDynamics) {
            FlyQiuTableConfig dynamicFormConfig = FlyQiuAvueColTools.getAvueDynamicFormConfig(config, dynamic);
            if (hasSynchronizationTable(dynamicFormConfig)) {
                return true;
            }
        }
        List<SqlColumnModel> tableColumnsOld = this.getStorageColumnConfig(config);
        FlyQiuColumnInfo flyQiuColumnInfo = new FlyQiuColumnInfo(columns, tableColumnsOld);
        return flyQiuColumnInfo.isUpdateTable();
    }

    /**
     * 删除数据表。
     *
     * @param formConfig 表配置
     */
    @Override
    public void deleteTable(FlyQiuTableConfig formConfig) {
        formEventManage.beforeDeleteTable(formConfig);
        flyQiuAvueDynamicService.deleteTable(formConfig);
        storageDeleteTable(formConfig);
        flyQiuTableConfigService.removeById(formConfig.getId());
        formEventManage.afterDeleteTable(formConfig);
    }

    /**
     * 存储器删除数据表。
     *
     * @param formConfig 表配置
     */
    protected abstract void storageDeleteTable(FlyQiuTableConfig formConfig);

    /**
     * 同步数据表。
     *
     * @param formConfig 表配置
     */
    @Override
    public final void synchronizationTable(FlyQiuTableConfig formConfig) {
        JSONObject formOption = formConfig.getFormOption();
        if (formOption == null || formOption.isEmpty()) {
            throw new FlyQiuFormException("未找到有效的表单配置");
        }
        List<SqlColumnModel> oldColumns = this.getStorageColumnConfig(formConfig);
        if (FlyQiuAvueColTools.isDynamic(formOption)) {
            formOption = FlyQiuAvueColTools.getDynamicFormOption(formOption);
            if (formOption == null || formOption.isEmpty()) {
                throw new FlyQiuFormException("未找到有效的表单配置");
            }
        }
        formEventManage.beforeSynchronizationTable(formConfig);

        JSONArray column = FlyQiuTableOptionTools.getColumns(formOption, true);

        FlyQiuColumnInfo flyQiuColumnInfo = new FlyQiuColumnInfo(column, oldColumns);
        flyQiuAvueDynamicService.syncDynamicTable(formConfig);
        List<SqlColumnModel> storeFormColumns;
        try {
            storeFormColumns = storageSynchronizationTable(formConfig, flyQiuColumnInfo);
        } catch (Exception e) {
            if (e instanceof SQLSyntaxErrorException) {
                throw new FlyQiuFormException("字段配置错误: " + e.getMessage());
            }
            throw e;
        }
        updateTableOption(storeFormColumns, formOption);
        long count = flyQiuTableConfigService.getTableHistoryCount(formConfig.getTableName());
        formConfig.setDeploymentStatus(FlyQiuFormDeploymentStatus.PUBLISHED.getValue());
        if (StringUtils.isAllBlank(formConfig.getId())) { // 首次子表单同步问题
            formConfig.setTablePreVersion(count);
            formConfig.setTableVersion(count + 1);
            formConfig.setFormOption(formOption);
            flyQiuTableConfigService.save(formConfig);
        } else if (formConfig.getTableVersion() > 0) { // 强制更新当前版本
            formConfig.setFormOption(formOption);
            flyQiuTableConfigService.updateById(formConfig);
        } else { // 默认调整版本
            formConfig.setTablePreVersion(count);
            formConfig.setTableVersion(count + 1);
            formConfig.setFormOption(formOption);
            flyQiuTableConfigService.updateById(formConfig);
            formConfig.setId(null);
            formConfig.setTableVersion(0L);
            formConfig.setTablePreVersion(count + 1);
            flyQiuTableConfigService.save(formConfig);
        }
        formEventManage.afterSynchronizationTable(formConfig, storeFormColumns, flyQiuColumnInfo);
    }

    /**
     * 执行数据表同步操作。
     *
     * @param formConfig       表配置
     * @param flyQiuColumnInfo 列信息
     * @return 同步后的列信息列表
     */
    protected abstract List<SqlColumnModel> storageSynchronizationTable(FlyQiuTableConfig formConfig, FlyQiuColumnInfo flyQiuColumnInfo);

    /**
     * 保存数据。
     *
     * @param config 表配置
     * @param data   待保存的数据
     * @return 数据 ID
     */
    @Override
    public final String save(FlyQiuTableConfig config, JSONObject data) {
        List<SqlColumnModel> columns = getStorageColumnConfig(config);
        flyQiuDataRuleManage.validateForm(config, data, FlyQiuFormDataAction.ADD);
        formDataEventManage.beforeSaveData(config, data);
        FlyQiuFormDataDeleteInvoke.get(config).invoke(data);
        String dataId = storageSave(config, columns, data);
        flyQiuAvueDynamicService.save(config, dataId, data);
        formDataEventManage.afterSaveData(config, data);
        return dataId;
    }

    /**
     * 存储器保存数据。
     *
     * @param config  表配置
     * @param columns 列信息
     * @param data    待保存的数据
     * @return 数据 ID
     */
    protected abstract String storageSave(FlyQiuTableConfig config, List<SqlColumnModel> columns, JSONObject data);

    /**
     * 删除数据。
     *
     * @param config       表配置
     * @param queryWrapper 删除条件
     * @return 删除数量
     */
    @Override
    public final long remove(FlyQiuTableConfig config, FlyQiuQueryWrapper queryWrapper) {
        formDataEventManage.beforeDelete(config, queryWrapper);
        FlyQiuFormDataDeleteInvoke flyQiuFormDataDeleteInvoke = FlyQiuFormDataDeleteInvoke.get(config);
        long count = 0L;
        if (flyQiuFormDataDeleteInvoke.getDataDelMode() == FlyQiuFormDataDelMode.PHYSICS_DEL) {
            count = physicsDel(config, queryWrapper);
        } else {
            JSONObject jsonObject = new JSONObject();
            flyQiuFormDataDeleteInvoke.invoke(queryWrapper, jsonObject, true);
            count = update(config, jsonObject, queryWrapper, true);
        }
        formDataEventManage.afterDelete(config, queryWrapper);
        return count;
    }

    /**
     * 物理删除数据。
     *
     * @param config       表配置
     * @param queryWrapper 删除条件
     * @return 删除数量
     */
    private long physicsDel(FlyQiuTableConfig config, FlyQiuQueryWrapper queryWrapper) {
        List<SqlColumnModel> column = getStorageColumnConfig(config);
        List<JSONObject> jsonObjects = storageList(config, column, queryWrapper);
        long count = storageRemove(config, queryWrapper);
        for (JSONObject jsonObject : jsonObjects) {
            String mainDataId = jsonObject.getString(COLUMN_PK_NAME);
            flyQiuAvueDynamicService.remove(config, mainDataId);
        }
        return count;
    }

    /**
     * 存储器删除数据。
     *
     * @param config       表配置
     * @param queryWrapper 删除条件
     * @return 删除数量
     */
    protected abstract long storageRemove(FlyQiuTableConfig config, FlyQiuQueryWrapper queryWrapper);

    /**
     * 更新数据。
     *
     * @param config       表配置
     * @param data         新数据
     * @param queryWrapper 更新条件
     * @return 更新数量
     */
    @Override
    public final long update(FlyQiuTableConfig config, JSONObject data, FlyQiuQueryWrapper queryWrapper) {
        formDataEventManage.beforeUpdate(config, data, queryWrapper);
        flyQiuDataRuleManage.validateForm(config, data, FlyQiuFormDataAction.UPDATE);
        long num = update(config, data, queryWrapper, false);
        formDataEventManage.afterUpdate(config, data, queryWrapper);
        return num;
    }

    /**
     * 实际执行更新操作。
     *
     * @param config       表配置
     * @param data         新数据
     * @param queryWrapper 更新条件
     * @param isDel        是否为删除操作
     * @return 更新数量
     */
    private long update(FlyQiuTableConfig config, JSONObject data, FlyQiuQueryWrapper queryWrapper, boolean isDel) {
        List<SqlColumnModel> column = getStorageColumnConfig(config);
        List<JSONObject> jsonObjects = storageList(config, column, queryWrapper);
        FlyQiuFormDataDeleteInvoke.get(config).invoke(queryWrapper, data, isDel);
        Long num = storageUpdate(config, column, data, queryWrapper);
        if (num == null) {
            num = 0L;
        }
        for (JSONObject jsonObject : jsonObjects) {
            String mainDataId = jsonObject.getString(COLUMN_PK_NAME);
            flyQiuAvueDynamicService.update(config, mainDataId, data);
        }
        return num;
    }

    /**
     * 存储器更新数据。
     *
     * @param config       表配置
     * @param columns      列信息
     * @param data         新数据
     * @param queryWrapper 更新条件
     * @return 更新数量
     */
    protected abstract Long storageUpdate(FlyQiuTableConfig config, List<SqlColumnModel> columns, JSONObject data, FlyQiuQueryWrapper queryWrapper);

    /**
     * 分页查询数据。
     *
     * @param page   分页信息
     * @param config 表配置
     * @param query  查询条件
     * @return 分页结果
     */
    @Override
    public final Page page(FlyQiuTableConfig config, Page page, FlyQiuQueryWrapper query) {
        List<SqlColumnModel> column = this.getStorageColumnConfig(config);
        formDataEventManage.beforeQueryData(config, query);
        FlyQiuFormDataDeleteInvoke.get(config).invoke(query);
        Page resultPage = storagePage(config, page, column, query);
        List records = resultPage.getRecords();
        JSONObject[] dataList = new JSONObject[records.size()];
        for (int i = 0; i < records.size(); i++) {
            dataList[i] = JSONObject.from(records.get(i));
        }
        records.clear();
        formDataEventManage.afterQueryData(config, query, dataList);
        resultPage.setRecords(Arrays.asList(dataList));
        return resultPage;
    }

    protected abstract Page storagePage(FlyQiuTableConfig config, Page page, List<SqlColumnModel> column, FlyQiuQueryWrapper query);


    @Override
    public final List<JSONObject> list(FlyQiuTableConfig config, FlyQiuQueryWrapper query) {
        List<SqlColumnModel> column = this.getStorageColumnConfig(config);
        formDataEventManage.beforeQueryData(config, query);
        FlyQiuFormDataDeleteInvoke.get(config).invoke(query);
        List<JSONObject> list = storageList(config, column, query);
        JSONObject[] dataList = new JSONObject[list.size()];
        for (int i = 0; i < list.size(); i++) {
            JSONObject item = JSONObject.from(list.get(i));
            flyQiuAvueDynamicService.handlerDynamicSelect(config, item);
            dataList[i] = item;
        }
        list.clear();
        formDataEventManage.afterQueryData(config, query, dataList);
        return Arrays.asList(dataList);
    }


    /**
     * 存储器根据查询条件查询 数据
     *
     * @param config 数据表配置
     * @param column 列信息
     * @param query  查询条件
     * @return 数据集合
     */
    protected abstract List<JSONObject> storageList(FlyQiuTableConfig config, List<SqlColumnModel> column, FlyQiuQueryWrapper query);


    /**
     * 查询数据数量
     *
     * @param config       数据表配置
     * @param queryWrapper 条件
     * @return 数据数量
     */
    @Override
    public final long count(FlyQiuTableConfig config, FlyQiuQueryWrapper queryWrapper) {
        formDataEventManage.beforeCount(config, queryWrapper);
        FlyQiuFormDataDeleteInvoke.get(config).invoke(queryWrapper);
        long count = storageCount(config, queryWrapper);
        formDataEventManage.afterCount(config, queryWrapper);
        return count;
    }

    /**
     * 查询数据数量
     *
     * @param config       数据表配置
     * @param queryWrapper 查询条件
     * @return 数据数量
     */
    protected abstract long storageCount(FlyQiuTableConfig config, FlyQiuQueryWrapper queryWrapper);

}
